package algebra.query.od;

import java.util.LinkedList;
import java.util.List;

import option.QueryKeywords;

import reasoner.KBReason;
import utils.exception.CoreReasoningException;
import utils.exception.OrderingDescriptionException;
import entities.assertion.ConceptAssertion;
import entities.concept.AndConcept;
import entities.concept.Concept;
import entities.concept.DomainConceptEQ;
import entities.concept.DomainConceptLT;
import entities.role.Role;

/**
 * A major sort on feature f
 * 
 * @author j55wu
 * 
 */

public class OrderDepFeature extends OrderDep {
	private OrderDep sub;
	private Role f;

	public OrderDepFeature(Role f, OrderDep sub) {
		this.sub = sub;
		this.f = f;
	}

	public OrderDep getSubOd() {
		return this.sub;
	}

	public Role getOdFeature() {
		return this.f;
	}

	protected int compareFeature(ConceptAssertion ca, ConceptAssertion ca2)
			throws OrderingDescriptionException, CoreReasoningException {
		if (compareOptimization) {
			// check for syntactic feature values first
			List<String> k1List = structuralFindK(ca, this.f);
			List<String> k2List = structuralFindK(ca2, this.f);
			if (k1List.size() == 1 && k2List.size() == 1) {
				// only if both CAs have one value for f
				String k = k1List.get(0);
				String k2 = k2List.get(0);
				int leveltop = k.compareTo(k2);
				return leveltop > 0 ? 1 : (leveltop == 0 ? this.sub.compare(ca,
						ca2) : -1);
			}
		}
		Concept lhs = new AndConcept(ca.getConcept(), ca2.getConcept()
				.getPrimeCopy());
		Role fp = this.f.getPrimeCopy();
		Concept rhs = new DomainConceptLT<Role, Role>(this.f, fp);
		KBReason reason = new KBReason(false);
		if (reason.subsumes(lhs, rhs, null)) {
			return -1;
		}
		rhs = new DomainConceptLT<Role, Role>(fp, f);
		if (reason.subsumes(lhs, rhs, null)) {
			return 1;
		}
		rhs = new DomainConceptEQ<Role, Role>(fp, f);
		if (reason.subsumes(lhs, rhs, null)) {
			return this.sub.compare(ca, ca2);
		}
		return 0;
	}

	// find all the values of k s.t. f=k is a conjunct of C in a:C
	private List<String> structuralFindK(ConceptAssertion ca, Role f) {
		LinkedList<String> result = new LinkedList<String>();
		LinkedList<Concept> q = new LinkedList<Concept>();
		q.add(ca.getConcept());
		while (!q.isEmpty()) {
			Concept con = q.remove();
			if (con instanceof AndConcept) {
				for (Concept and : ((AndConcept) con).getConceptSet()) {
					q.add(and);
				}
			}
			if (con instanceof DomainConceptEQ) {
				DomainConceptEQ<?, ?> bk = (DomainConceptEQ<?, ?>) con;
				if (bk.getRealFeature() != null
						&& bk.getRealFeature().equals(f)) {
					if (bk.getRealValue() != null) {
						result.add((String) bk.getRealValue());
					}

				}
			}
		}
		return result;
	}

	@Override
	public String toString() {
		return "(OD: " + f.toString() + " " + sub.toString() + ")";
	}

	@Override
	public String toSerializedString() {
		return "(" + QueryKeywords.Od_Feat + " " + this.f.getRoleName() + " "
				+ this.sub.toSerializedString() + ")";
	}

	private volatile int hashCode = 0;
	@Override
	public int hashCode() {
		if (hashCode != 0) {
			return hashCode;
		}
		final int prime = 31;
		int result = 1;
		result = prime * result + ((f == null) ? 0 : f.hashCode());
		result = prime * result + ((sub == null) ? 0 : sub.hashCode());
		hashCode = result;
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		OrderDepFeature other = (OrderDepFeature) obj;
		if (f == null) {
			if (other.f != null)
				return false;
		} else if (!f.equals(other.f))
			return false;
		if (sub == null) {
			if (other.sub != null)
				return false;
		} else if (!sub.equals(other.sub))
			return false;
		return true;
	}
	
	
	

}
